/**
 * @(#) MySQLHandshark41.java RabbitDB
 */
package cn.rabbitdb.protocol.mysql41;

import cn.rabbitdb.protocol.MySQLMessageReader;
import cn.rabbitdb.protocol.MySQLMessageWriter;
import io.netty.buffer.ByteBuf;
import lombok.Getter;
import lombok.ToString;

/**
 * @author 智慧工厂@M
 *
 */
@Getter
@ToString
public class MySQLHandshark41 extends MySQLPacket {
	private final int protocolVersion;
	private final String serverVersion;
	private final int threadId;
	private final byte[] authPluginDataPart1;
	private final int capabilityFlags;
	private final int charsetIndex;
	private final int statusFlags;
	private final int authPluginDataLen;
	private final byte[] authPluginDataPart2;
	private final String authPluginName;
	private byte[] capabilitiFlags1;
	private byte[] capabilitiFlags2;

	/**
	 * @param buffer
	 */
	public MySQLHandshark41(ByteBuf buffer) {
		super(buffer);
		MySQLMessageReader reader = getReader();
		this.protocolVersion = reader.readUB();
		this.serverVersion = reader.readStringWithNull();
		this.threadId = (int) reader.readUB4();
		this.authPluginDataPart1 = reader.readBytes(8);
		reader.skip(1);
		capabilitiFlags1 = reader.readBytes(2);
		this.charsetIndex = reader.readUB();
		this.statusFlags = reader.readUB2();
		capabilitiFlags2 = reader.readBytes(2);
		byte[] capabilitiesBuffer = new byte[4];
		capabilitiesBuffer[0] = capabilitiFlags2[0];
		capabilitiesBuffer[1] = capabilitiFlags2[1];
		capabilitiesBuffer[2] = capabilitiFlags1[0];
		capabilitiesBuffer[3] = capabilitiFlags1[1];
		int i = capabilitiesBuffer[0] & 0xff;
		i |= (capabilitiesBuffer[1] & 0xff) << 8;
		i |= (capabilitiesBuffer[2] & 0xff) << 16;
		i |= (capabilitiesBuffer[3] & 0xff) << 24;
		this.capabilityFlags = i;

		if ((this.capabilityFlags & MySQLCapabilityFlags.CLIENT_PLUGIN_AUTH) != 0) {
			this.authPluginDataLen = reader.readUB();
		} else {
			this.authPluginDataLen = 0;
		}
		reader.skip(10);
		if ((this.capabilityFlags & MySQLCapabilityFlags.CLIENT_PLUGIN_AUTH) != 0) {
			this.authPluginDataPart2 = reader.readBytesWithNull();
			// reader.skip(1);
			this.authPluginName = new String(reader.readBytesWithNull());
		} else {
			this.authPluginDataPart2 = reader.readBytesWithNull();
			this.authPluginName = null;
		}

		reader.skip(reader.getBuffer().readableBytes());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.mysql.ddal.protocol.mysql41.MySQLPacket#getMySQLMessageWriter()
	 */
	@Override
	public MySQLMessageWriter getMySQLMessageWriter() {
		MySQLMessageWriter writer = new MySQLMessageWriter();
		writer.writeUB3(this.getPacketLength());
		writer.writeUB((byte) this.getPacketId());
		writer.writeUB((byte) this.protocolVersion);
		writer.writeStringWithNull(this.serverVersion);
		writer.writeUB4(this.threadId);
		writer.writeBytes(this.authPluginDataPart1);
		writer.writeUB((byte) 0);
		writer.writeBytes(this.capabilitiFlags1);
		writer.writeUB((byte) charsetIndex);
		writer.writeUB2(this.statusFlags);
		writer.writeBytes(this.capabilitiFlags2);
		if ((this.capabilityFlags & MySQLCapabilityFlags.CLIENT_PLUGIN_AUTH) != 0) {
			writer.writeUB((byte) this.authPluginDataLen);
		}

		writer.writeBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
		if ((this.capabilityFlags & MySQLCapabilityFlags.CLIENT_PLUGIN_AUTH) != 0) {
			writer.writeBytesWithNull(this.authPluginDataPart2);
			writer.writeStringWithNull(this.authPluginName);
		} else {
			writer.writeBytesWithNull(this.authPluginDataPart2);
		}
		return writer;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.mysql.ddal.protocol.mysql41.MySQLPacket#calucatePacketLength()
	 */
	@Override
	public int calucatePacketLength() {
		int length = 0;
		// length += 1; // packet_id
		length += 1; // protocolVersion
		length += this.serverVersion.getBytes().length + 1; // serverVersion
		length += 4; // threadID
		length += 8; // authPluginDataPart1
		length += 1; // skip
		length += 2; // capability_flags_1
		length += 1; // charsetIndex
		// length += 2; // statusFlags
		length += 4; // capabilitiesBuffer
		if ((this.capabilityFlags & MySQLCapabilityFlags.CLIENT_PLUGIN_AUTH) != 0) {
			length += 1;
		}

		length += 10;

		if ((this.capabilityFlags & MySQLCapabilityFlags.CLIENT_PLUGIN_AUTH) != 0) {
			// this.authPluginDataPart2 = reader.readBytesWithNull();
			length += this.authPluginDataPart2.length + 1;
			// this.authPluginName = new String(reader.readBytesWithNull());
			length += this.authPluginName.getBytes().length + 1;
		} else {
			length += this.authPluginDataPart2.length + 1;
		}
		return length;
	}

	/**
	 * @param packetLength
	 * @param packetId
	 * @param protocolVersion
	 * @param serverVersion
	 * @param threadId
	 * @param authPluginDataPart1
	 * @param capabilityFlags
	 * @param charsetIndex
	 * @param statusFlags
	 * @param authPluginDataLen
	 * @param authPluginDataPart2
	 * @param authPluginName
	 */
	public MySQLHandshark41(int packetId, int protocolVersion, String serverVersion, int threadId,
			byte[] authPluginDataPart1, int capabilityFlags, int charsetIndex, int statusFlags, int authPluginDataLen,
			byte[] authPluginDataPart2, String authPluginName) {
		super(0, packetId);
		this.protocolVersion = protocolVersion;
		this.serverVersion = serverVersion;
		this.threadId = threadId;
		this.authPluginDataPart1 = authPluginDataPart1;
		this.capabilityFlags = capabilityFlags;
		this.charsetIndex = charsetIndex;
		this.statusFlags = statusFlags;
		this.authPluginDataLen = authPluginDataLen;
		this.authPluginDataPart2 = authPluginDataPart2;
		this.authPluginName = authPluginName;
		this.capabilitiFlags1 = new byte[] { (byte) 255, (byte) 247 };
		this.capabilitiFlags2 = new byte[] { (byte) 255, (byte) 129 };
		this.setPacketLength(this.calucatePacketLength());
	}

}
